// ECE556 - Copyright 2013 University of Wisconsin-Madison.  All Rights Reserved.

#include "ece556.h"
#include "foo.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <math.h>
#define LEN     60
#define EDGE_NUM (rst->gx)*(rst->gy - 1) + (rst->gy)*(rst->gx - 1)

routingInst *readBenchmark(const char *fileName)
{
 	routingInst *rst;
        if ( !(rst = (routingInst*)malloc(sizeof(routingInst))))
                exit (0);
        FILE            *fp = fopen (fileName, "r");
        char            line[LEN];

        int             cap;            //      default capacity
        int             num_net;        //      num net
        int             num_blk = 0;        //      blockage
        int             cnt_net = 0;
        int             cnt_pin = 0;
        int             num_pin = 0;

        char    str[LEN];
        while ( fgets (line, LEN, fp) )
        {
                if (sscanf ( line, "grid\t%d %d", &(rst->gx), &(rst->gy) ))
                {
                        rst->edgeCaps = new_array ( EDGE_NUM );
                        rst->edgeUtils = new_array ( EDGE_NUM );
                        rst->nodeUtils = new_array ( rst->gx * rst->gy );
                        assign_array ( rst->nodeUtils, rst->gx * rst->gy, 0 );
                        rst->edgeWeights = new_float_array ( EDGE_NUM );
                        continue;
                }       //      gx,gy
                if (sscanf ( line, "capacity\t%d", &cap ))
                {
                        assign_array ( rst->edgeCaps, EDGE_NUM, cap );
                        assign_array ( rst->edgeUtils, EDGE_NUM, 0 );
                        continue;
                }       //      default capacity
                if (sscanf ( line, "num net %d", &num_net ))
                {
                        if (!(rst->nets = (net*)calloc(num_net, sizeof(net))))
                                exit (0);
                        cnt_net = -1; 
                        continue;
                }       //      num_net
                //      read net information
                if ( !strncmp (line, "n", 1) )
                {
                        ++ cnt_net;
                        char    *first_space = strchr ( line, ' ' );
                        strncpy ( str, first_space+1, LEN );
                        num_pin = atoi (str);
                        rst->nets[cnt_net].id = cnt_net; 
                        rst->nets[cnt_net].numPins = num_pin;
                        rst->nets[cnt_net].pins = new_array ( num_pin );
                        rst->nets[cnt_net].edges = new_int_LL ();
                        rst->nets[cnt_net].nodes = new_int_LL ();
                        if (!(rst->nets[cnt_net].r = (route*)calloc( num_pin-1, sizeof(route))))
                                exit (0);
                        cnt_pin = 0;
                        continue;
                }
                /* still reading pin info*/
                if ( (cnt_net < num_net) && (cnt_pin < num_pin) )
                {
                        int     x, y;
                        sscanf (line, "%d %d\n", &x, &y);
                        rst->nets[cnt_net].pins[cnt_pin] = pos_to_id ( x, y, rst );
                        rst->nodeUtils[y*rst->gx+x] = 1;
                        ++ cnt_pin;
                        continue;
                }
                if ( !num_blk )
                {
                        num_blk = atoi (line);
                        continue;
                }
                //      read blk info
                int     x1, y1, x2, y2, c;
                sscanf (line, "%d %d %d %d %d", &x1,&y1,&x2,&y2,&c);
                int     edge_id = find_edge_id (x1, y1, x2, y2, rst);
                rst->edgeCaps[edge_id] = c;
        }

        rst->cap = cap;
        rst->numNets = num_net;
        rst->numEdges = EDGE_NUM;

        rst->netWeights = new_float_array (rst->numNets);
        assign_float_array ( rst->netWeights, rst->numNets, 0 );

        rst->edgeWeights = new_float_array (EDGE_NUM);
        assign_float_array ( rst->edgeWeights, EDGE_NUM, 0 );
        
        rst->hist = new_float_array ( EDGE_NUM );
        assign_float_array ( rst->hist, EDGE_NUM, 1 );

        printf ( "\nReading Benchmark :\n\n" );
        printf ( "\tGrid dimension :\t%d X %d\n", rst->gx, rst->gy );
        printf ( "\tEdge number :\t\t%d\n", rst->numEdges );
        printf ( "\tNet number :\t\t%d\n", rst->numNets );
        printf ( "\tDefault capacity :\t%d\n", cap );
        printf ( "\tBlockage number :\t%d\n", num_blk );
        
        return  rst;
}
int solveRouting(routingInst *rst)
{
        clock_t begin, end;
        double  time_spent;
        begin = clock();

        for ( int i = 0; i< rst->numNets; i++)
                pin_ordering ( i, rst );
        
        int     *net_order = net_ordering (rst);

        for ( int i = rst->numNets-1; i>=0; i-- )
                smart_net_route ( net_order[i], rst );
        refresh ( rst );
        int     cur = ofl ( rst );

        for ( int i = 0; i < rst->numNets; i++ )
                if ( rst->netWeights[net_order[i]] )
                        net_order[i] = -1;
                else
                        rip_up ( net_order[i],rst );
        int     width;
        for ( int i = rst->numNets-1; i>=0; i-- )
                if ( net_order[i] != -1 )
                {
                        width = sqrt(cur)/100 * 5;
                        A_star_net_route ( net_order[i], rst, width );
                        refresh ( rst );
                        cur = ofl ( rst );
                        printf ( "%d\t%d\n", i, cur );
                }

        refresh ( rst );        

//        int     *sort = sort_array ( rst->netWeights, rst->numNets );
//        int     non_zero = non_zero_array ( rst->netWeights, rst->numNets );


        printf ( "%d\n", ofl(rst) );

        end = clock();
        time_spent = (double)(end-begin)/CLOCKS_PER_SEC;
        printf ( "running time : %.2f\n", time_spent );

        return  1;
}

int writeOutput(const char *outRouteFile, routingInst *rst)
{
  /*********** TO BE FILLED BY YOU **********/
        FILE *fp = fopen ( outRouteFile, "w" );
        ptr_rst ( fp, rst );
        return 1;
}

int release(routingInst *rst)
{
  /*********** TO BE FILLED BY YOU **********/
        free ( rst );
  return 1;
}
